import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Pattern;

public class Tetris extends JFrame {
    private static final long serialVersionUID = 1L;
    public static final int BOARD_WIDTH = 10;
    public static final int BOARD_HEIGHT = 22;
    private JLabel statusbar;
    private Board board;
    private ScoreDatabase scoreDB;
    private static final Logger LOGGER = Logger.getLogger(Tetris.class.getName());
    private String currentUser; // 当前登录用户

    public Tetris() throws SQLException {
        try {
            checkMySQLDriver();
            scoreDB = new ScoreDatabase();
            if (!scoreDB.isConnected()) {
                throw new Exception("数据库连接失败");
            }
            System.out.println("数据库连接成功");
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "数据库初始化失败", e);
            JOptionPane.showMessageDialog(this,
                    "无法连接数据库: " + e.getMessage(),
                    "错误", JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }

        if (!showLoginRegisterDialog()) {
            System.exit(0);
        }

        initGame();
    }

    private boolean showLoginRegisterDialog() {
        Object[] options = {"登录", "注册", "取消"};
        int choice = JOptionPane.showOptionDialog(this,
                "请选择操作:", "用户登录",
                JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE,
                null, options, options[0]);

        if (choice == JOptionPane.CLOSED_OPTION || choice == 2) {
            return false;
        }

        try {
            if (choice == 0) { // 登录
                return handleLogin();
            } else { // 注册
                return handleRegister();
            }
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "认证过程出错", e);
            JOptionPane.showMessageDialog(this,
                    "认证失败: " + e.getMessage(),
                    "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
    }

    private boolean handleLogin() throws SQLException, NoSuchAlgorithmException {
        if (scoreDB == null) {
            JOptionPane.showMessageDialog(this, "数据库未连接，请重启游戏", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return false;
        }

        JPanel panel = new JPanel(new GridLayout(3, 2, 10, 10));
        panel.add(new JLabel("用户名:"));
        JTextField usernameField = new JTextField();
        panel.add(usernameField);

        panel.add(new JLabel("密码:"));
        JPasswordField passwordField = new JPasswordField();
        panel.add(passwordField);

        int result = JOptionPane.showConfirmDialog(this, panel, "登录",
                JOptionPane.OK_CANCEL_OPTION);
        if (result != JOptionPane.OK_OPTION) {
            return false;
        }

        String username = usernameField.getText().trim();
        String password = new String(passwordField.getPassword());

        if (username.isEmpty() || password.isEmpty()) {
            JOptionPane.showMessageDialog(this, "用户名或密码不能为空", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return handleLogin();
        }

        String hashedPassword = md5(password);
        if (scoreDB.validateUser(username, hashedPassword)) {
            currentUser = username;
            JOptionPane.showMessageDialog(this, "登录成功", "提示",
                    JOptionPane.INFORMATION_MESSAGE);
            return true;
        } else {
            JOptionPane.showMessageDialog(this, "用户名或密码错误", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return handleLogin();
        }
    }

    private boolean handleRegister() throws SQLException, NoSuchAlgorithmException {
        if (scoreDB == null) {
            JOptionPane.showMessageDialog(this, "数据库未连接，请重启游戏", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return false;
        }

        JPanel panel = new JPanel(new GridLayout(4, 2, 10, 10));
        panel.add(new JLabel("用户名:"));
        JTextField usernameField = new JTextField();
        panel.add(usernameField);

        panel.add(new JLabel("密码:"));
        JPasswordField passwordField = new JPasswordField();
        panel.add(passwordField);

        panel.add(new JLabel("确认密码:"));
        JPasswordField confirmPasswordField = new JPasswordField();
        panel.add(confirmPasswordField);

        panel.add(new JLabel("密码要求:"));
        panel.add(new JLabel("至少6位，包含字母和数字")); // 新增提示

        int result = JOptionPane.showConfirmDialog(this, panel, "注册",
                JOptionPane.OK_CANCEL_OPTION);
        if (result != JOptionPane.OK_OPTION) {
            return false;
        }

        String username = usernameField.getText().trim();
        String password = new String(passwordField.getPassword());
        String confirmPassword = new String(confirmPasswordField.getPassword());

        if (!validatePasswordStrength(password)) {
            JOptionPane.showMessageDialog(this,
                    "密码需至少6位，包含字母和数字",
                    "错误", JOptionPane.ERROR_MESSAGE);
            return handleRegister();
        }

        if (!password.equals(confirmPassword)) {
            JOptionPane.showMessageDialog(this, "两次密码不一致", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return handleRegister();
        }

        String hashedPassword = md5(password);
        if (scoreDB.isUsernameExists(username)) {
            JOptionPane.showMessageDialog(this, "用户名已存在", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return handleRegister();
        }

        scoreDB.registerUser(username, hashedPassword);
        JOptionPane.showMessageDialog(this, "注册成功，请登录", "提示",
                JOptionPane.INFORMATION_MESSAGE);
        return handleLogin();
    }

    private boolean validatePasswordStrength(String password) {
        String pattern = "^(?=.*[0-9])(?=.*[a-zA-Z]).{6,}$";
        return Pattern.matches(pattern, password);
    }

    private String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());
        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();
    }

    private void checkMySQLDriver() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            System.out.println("MySQL驱动加载成功");
        } catch (ClassNotFoundException e) {
            System.err.println("错误: 未找到MySQL驱动，请添加mysql-connector-java依赖");
            LOGGER.log(Level.SEVERE, "MySQL驱动加载失败", e);
            JOptionPane.showMessageDialog(this,
                    "驱动加载失败\n请检查类路径是否包含MySQL驱动",
                    "错误", JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }
    }

    private void initGame() throws SQLException {
        setTitle("俄罗斯方块 - 玩家：" + currentUser);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(false);

        statusbar = new JLabel("得分: 0");
        add(statusbar, BorderLayout.NORTH);

        board = new Board(this);
        add(board, BorderLayout.CENTER);

        createMenuBar();
        pack();
        setVisible(true);
        board.start();
    }

    private void createMenuBar() throws SQLException {
        JMenuBar menuBar = new JMenuBar();

        JMenu gameMenu = new JMenu("游戏");
        JMenuItem newGameItem = new JMenuItem("新游戏");
        newGameItem.addActionListener(e -> board.start());

        JMenuItem highScoresItem = new JMenuItem("高分榜");
        highScoresItem.addActionListener(e -> showHighScores());

        JMenuItem exitItem = new JMenuItem("退出");
        exitItem.addActionListener(e -> {
            if (scoreDB != null) {
                scoreDB.close();
            }
            System.exit(0);
        });

        gameMenu.add(newGameItem);
        gameMenu.addSeparator();
        gameMenu.add(highScoresItem);
        gameMenu.addSeparator();
        gameMenu.add(exitItem);

        JMenu helpMenu = new JMenu("帮助");
        JMenuItem controlsItem = new JMenuItem("操作说明");
        controlsItem.addActionListener(e -> showControls());

        JMenuItem aboutItem = new JMenuItem("关于");
        aboutItem.addActionListener(e -> showAbout());

        helpMenu.add(controlsItem);
        helpMenu.addSeparator();
        helpMenu.add(aboutItem);

        menuBar.add(gameMenu);
        menuBar.add(helpMenu);
        setJMenuBar(menuBar);
    }

    public void saveHighScore() {
        int currentScore = board.getNumLinesRemoved();
        if (currentScore > 0 && currentUser != null && scoreDB.isConnected()) {
            scoreDB.saveGameRecord(currentUser, currentScore);
            statusbar.setText("得分: " + currentScore);
            showHighScores();
        } else if (currentScore > 0 && !scoreDB.isConnected()) {
            JOptionPane.showMessageDialog(this, "数据库连接中断，无法保存分数",
                    "错误", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void showHighScores() {
        if (!scoreDB.isConnected()) {
            JOptionPane.showMessageDialog(this, "数据库未连接，无法获取高分榜",
                    "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }

        SwingWorker<Score[], Void> worker = new SwingWorker<Score[], Void>() {
            @Override
            protected Score[] doInBackground() {
                try {
                    return scoreDB.getTopScores(10);
                } catch (Exception e) {
                    LOGGER.log(Level.SEVERE, "获取高分数据失败", e);
                    return new Score[0];
                }
            }

            @Override
            protected void done() {
                try {
                    Score[] scores = get();
                    StringBuilder message = new StringBuilder("高分榜:\n\n");
                    if (scores.length == 0) {
                        message.append("暂无记录");
                    } else {
                        for (int i = 0; i < scores.length; i++) {
                            message.append(String.format("%2d. %-10s %d分 %s\n",
                                    i + 1, scores[i].name, scores[i].score, scores[i].date));
                        }
                    }
                    JOptionPane.showMessageDialog(Tetris.this, message.toString(),
                            "历史最高分", JOptionPane.INFORMATION_MESSAGE);
                } catch (Exception e) {
                    LOGGER.log(Level.SEVERE, "显示高分榜失败", e);
                }
            }
        };
        worker.execute();
    }

    private void showControls() {
        String message =
                "操作说明:\n\n" +
                        "←/→: 左右移动\n" +
                        "↑: 旋转方块\n" +
                        "↓: 加速下落\n" +
                        "空格: 直接落地\n" +
                        "P: 暂停/继续\n" +
                        "H: 查看高分榜\n" +
                        "N: 新游戏";

        JOptionPane.showMessageDialog(this, message, "操作指南",
                JOptionPane.INFORMATION_MESSAGE);
    }

    private void showAbout() {
        String message =
                "俄罗斯方块\n" +
                        "版本 1.2\n\n" +
                        "开发语言: Java\n" +
                        "数据库: MySQL\n" +
                        "支持功能: 用户系统、高分榜、难度自适应";

        JOptionPane.showMessageDialog(this, message, "关于游戏",
                JOptionPane.INFORMATION_MESSAGE);
    }



    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            try {
                new Tetris().setVisible(true);
            } catch (Exception e) {
                LOGGER.log(Level.SEVERE, "程序启动失败", e);
                JOptionPane.showMessageDialog(null,
                        "程序启动失败: " + e.getMessage(),
                        "错误", JOptionPane.ERROR_MESSAGE);
                System.exit(1);
            }
        });
    }

    enum Tetrominoes {
        NoShape, ZShape, SShape, LineShape,
        TShape, SquareShape, LShape, MirroredLShape
    }

    class Board extends JPanel implements ActionListener, KeyListener {
        private static final long serialVersionUID = 1L;
        private final int INITIAL_DELAY = 300; // 初始速度
        private int currentDelay;
        private Timer timer;
        private boolean isFallingFinished = false;
        private boolean isStarted = false;
        private boolean isPaused = false;
        private int numLinesRemoved = 0;
        private int curX = 0;
        private int curY = 0;
        private Shape curPiece;
        private Tetrominoes[] boardData;
        private Tetris parent;

        public Board(Tetris parent) {
            this.parent = parent;
            currentDelay = INITIAL_DELAY;
            initBoard();
        }

        private void initBoard() {
            setBackground(Color.BLACK);
            setFocusable(true);
            setPreferredSize(new Dimension(BOARD_WIDTH * 25, BOARD_HEIGHT * 25));

            timer = new Timer(currentDelay, this);
            timer.start();

            boardData = new Tetrominoes[BOARD_WIDTH * BOARD_HEIGHT];
            addKeyListener(this);
            clearBoard();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (isFallingFinished) {
                isFallingFinished = false;
                newPiece();
            } else {
                oneLineDown();
            }
        }

        private int squareSize() {
            return (int) getSize().getWidth() / BOARD_WIDTH;
        }

        private Tetrominoes getShapeAt(int x, int y) {
            return boardData[y * BOARD_WIDTH + x];
        }

        void start() {
            if (isPaused) {
                resumeGame();
                return;
            }

            isStarted = true;
            isPaused = false;
            numLinesRemoved = 0;
            clearBoard();
            newPiece();
            timer.start();
            parent.getStatusBar().setText("得分: 0");
        }

        private void resumeGame() {
            isPaused = false;
            timer.setDelay(currentDelay);
            timer.start();
            parent.getStatusBar().setText("得分: " + numLinesRemoved);
            repaint();
        }

        private void pauseGame() {
            isPaused = true;
            timer.stop();
            parent.getStatusBar().setText("暂停中");
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            drawBoard(g);
            drawPiece(g);
            drawPauseMessage(g);
        }

        private void drawBoard(Graphics g) {
            int squareSize = squareSize();
            int boardTop = getHeight() - BOARD_HEIGHT * squareSize;

            g.setColor(Color.DARK_GRAY);
            for (int i = 0; i < BOARD_HEIGHT; i++) {
                for (int j = 0; j < BOARD_WIDTH; j++) {
                    g.drawRect(j * squareSize, boardTop + i * squareSize,
                            squareSize, squareSize);
                }
            }

            for (int i = 0; i < BOARD_HEIGHT; i++) {
                for (int j = 0; j < BOARD_WIDTH; j++) {
                    Tetrominoes shape = getShapeAt(j, i);
                    if (shape != Tetrominoes.NoShape) {
                        drawSquare(g, j * squareSize, boardTop + i * squareSize, shape);
                    }
                }
            }
        }

        private void drawPiece(Graphics g) {
            if (curPiece.getShape() == Tetrominoes.NoShape) return;

            int squareSize = squareSize();
            int boardTop = getHeight() - BOARD_HEIGHT * squareSize;

            for (int i = 0; i < 4; i++) {
                int x = curX + curPiece.x(i);
                int y = curY - curPiece.y(i);
                drawSquare(g, x * squareSize, boardTop + (BOARD_HEIGHT - y - 1) * squareSize,
                        curPiece.getShape());
            }
        }

        private void drawPauseMessage(Graphics g) {
            if (isPaused) {
                g.setColor(Color.WHITE);
                g.setFont(new Font("微软雅黑", Font.BOLD, 24));
                FontMetrics fm = g.getFontMetrics();
                String msg = "游戏暂停";
                g.drawString(msg, (getWidth() - fm.stringWidth(msg)) / 2, getHeight() / 2);
            }
        }

        private void dropDown() {
            int newY = curY;
            while (newY > 0 && tryMove(curPiece, curX, newY - 1)) {
                newY--;        }
                pieceDropped();
            }
        
            private void oneLineDown() {
                if (!tryMove(curPiece, curX, curY - 1)) {
                    pieceDropped();
                }
            }
        
            private void clearBoard() {
                for (int i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; i++) {
                    boardData[i] = Tetrominoes.NoShape;
                }
            }
        
            private void pieceDropped() {
                for (int i = 0; i < 4; i++) {
                    int x = curX + curPiece.x(i);
                    int y = curY - curPiece.y(i);
                    boardData[y * BOARD_WIDTH + x] = curPiece.getShape();
                }
        
                removeFullLines();
        
                if (!isFallingFinished) {
                    newPiece();
                }
            }
        
            private void newPiece() {
                curPiece = new Shape();
                curPiece.setRandomShape();
                curX = BOARD_WIDTH / 2 - 1;
                curY = BOARD_HEIGHT - 1 + curPiece.minY();
        
                if (!tryMove(curPiece, curX, curY)) {
                    curPiece.setShape(Tetrominoes.NoShape);
                    timer.stop();
                    isStarted = false;
                    parent.getStatusBar().setText("游戏结束");
        
                    // 保存高分
                    SwingUtilities.invokeLater(() -> {
                        parent.saveHighScore();
        
                        // 询问是否开始新游戏
                        int response = JOptionPane.showConfirmDialog(this,
                                "游戏结束！是否开始新游戏?", "游戏结束",
                                JOptionPane.YES_NO_OPTION);
                        if (response == JOptionPane.YES_OPTION) {
                            start();
                        }
                    });
                }
            }
        
            private boolean tryMove(Shape newPiece, int newX, int newY) {
                for (int i = 0; i < 4; i++) {
                    int x = newX + newPiece.x(i);
                    int y = newY - newPiece.y(i);
                    if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) {
                        return false;
                    }
                    if (getShapeAt(x, y) != Tetrominoes.NoShape) {
                        return false;
                    }
                }
        
                curPiece = newPiece;
                curX = newX;
                curY = newY;
                repaint();
                return true;
            }
        
            private void removeFullLines() {
                int linesRemoved = 0;
        
                for (int i = BOARD_HEIGHT - 1; i >= 0; i--) {
                    boolean isLineFull = true;
        
                    for (int j = 0; j < BOARD_WIDTH; j++) {
                        if (getShapeAt(j, i) == Tetrominoes.NoShape) {
                            isLineFull = false;
                            break;
                        }
                    }
        
                    if (isLineFull) {
                        linesRemoved++;
                        for (int k = i; k < BOARD_HEIGHT - 1; k++) {
                            for (int j = 0; j < BOARD_WIDTH; j++) {
                                boardData[k * BOARD_WIDTH + j] = getShapeAt(j, k + 1);
                            }
                        }
                    }
                }
        
                if (linesRemoved > 0) {
                    // 根据消除的行数增加分数
                    switch (linesRemoved) {
                        case 1:
                            numLinesRemoved += 100;
                            break;
                        case 2:
                            numLinesRemoved += 300;
                            break;
                        case 3:
                            numLinesRemoved += 500;
                            break;
                        case 4:
                            numLinesRemoved += 800;
                            break;
                    }
        
                    parent.getStatusBar().setText("得分: " + numLinesRemoved);
                    isFallingFinished = true;
                    curPiece.setShape(Tetrominoes.NoShape);
                    repaint();
        
                    // 根据分数调整游戏速度
                    if (numLinesRemoved % 1000 == 0 && currentDelay > 100) {
                        currentDelay = INITIAL_DELAY - (numLinesRemoved / 1000 * 20);
                        timer.setDelay(currentDelay);
                    }
                }
            }
        
            private void drawSquare(Graphics g, int x, int y, Tetrominoes shape) {
                Color colors[] = {
                        new Color(0, 0, 0),        // NoShape
                        new Color(255, 0, 0),      // ZShape
                        new Color(0, 255, 0),      // SShape
                        new Color(0, 0, 255),      // LineShape
                        new Color(255, 255, 0),    // TShape
                        new Color(255, 165, 0),    // SquareShape
                        new Color(0, 255, 255),    // LShape
                        new Color(128, 0, 128)     // MirroredLShape
                };
        
                Color color = colors[shape.ordinal()];
        
                // 填充方块主体
                g.setColor(color);
                g.fillRect(x + 1, y + 1, squareSize() - 2, squareSize() - 2);
        
                // 添加高亮边缘
                g.setColor(color.brighter());
                g.fillRect(x + 1, y + 1, squareSize() - 2, 2);
                g.fillRect(x + 1, y + 1, 2, squareSize() - 2);
        
                // 添加阴影边缘
                g.setColor(color.darker());
                g.fillRect(x + 1, y + squareSize() - 2, squareSize() - 2, 2);
                g.fillRect(x + squareSize() - 2, y + 1, 2, squareSize() - 2);
            }
        
            @Override
            public void keyPressed(KeyEvent e) {
                if (!isStarted || curPiece.getShape() == Tetrominoes.NoShape) {
                    return;
                }
        
                int keycode = e.getKeyCode();
        
                if (keycode == 'P' || keycode == 'p') {
                    if (isPaused) {
                        resumeGame();
                    } else {
                        pauseGame();
                    }
                    return;
                }
        
                if (isPaused) {
                    return;
                }
        
                switch (keycode) {
                    case KeyEvent.VK_LEFT:
                        tryMove(curPiece, curX - 1, curY);
                        break;
                    case KeyEvent.VK_RIGHT:
                        tryMove(curPiece, curX + 1, curY);
                        break;
                    case KeyEvent.VK_DOWN:
                        tryMove(curPiece.rotateRight(), curX, curY);
                        break;
                    case KeyEvent.VK_UP:
                        tryMove(curPiece.rotateLeft(), curX, curY);
                        break;
                    case KeyEvent.VK_SPACE:
                        dropDown();
                        break;
                    case KeyEvent.VK_D:
                        oneLineDown();
                        break;
                    case KeyEvent.VK_H:
                        parent.showHighScores();
                        break;
                    case KeyEvent.VK_N:
                        start();
                        break;
                }
            }
    
            @Override
            public void keyReleased(KeyEvent e) {
            }
        
            @Override
            public void keyTyped(KeyEvent e) {
            }
        
            public int getNumLinesRemoved() {
                return numLinesRemoved;
            }
        }
    
        class Shape {
            private Tetrominoes pieceShape;
            private int[][] coords;
            private int[][][] coordsTable;
        
            public Shape() {
                coords = new int[4][2];
                setShape(Tetrominoes.NoShape);
            }
        
            void setShape(Tetrominoes shape) {
                coordsTable = new int[][][] {
                        { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
                        { { 0, -1 }, { 0, 0 }, { -1, 0 }, { -1, 1 } },
                        { { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } },
                        { { 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 } },
                        { { -1, 0 }, { 0, 0 }, { 1, 0 }, { 0, 1 } },
                        { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } },
                        { { -1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } },
                        { { 1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } }
                };
        
                for (int i = 0; i < 4; i++) {
                    System.arraycopy(coordsTable[shape.ordinal()][i], 0, coords[i], 0, 2);
                }
                pieceShape = shape;
            }
        
            private void setX(int index, int x) {
                coords[index][0] = x;
            }
        
            private void setY(int index, int y) {
                coords[index][1] = y;
            }
        
            int x(int index) {
                return coords[index][0];
            }
        
            int y(int index) {
                return coords[index][1];
            }
        
            Tetrominoes getShape() {
                return pieceShape;
            }
        
            void setRandomShape() {
                java.util.Random r = new java.util.Random();
                int x = Math.abs(r.nextInt()) % 7 + 1;
                Tetrominoes[] values = Tetrominoes.values();
                setShape(values[x]);
            }
        
            int minX() {
                int m = coords[0][0];
                for (int i = 0; i < 4; i++) {
                m = Math.min(m, coords[i][0]);
                }
                return m;
            }
        
            int minY() {
                int m = coords[0][1];
                for (int i = 0; i < 4; i++) {
                m = Math.min(m, coords[i][1]);
                }
                return m;
            }
        
            Shape rotateLeft() {
                if (pieceShape == Tetrominoes.SquareShape) {
                    return this;
                }
        
                Shape result = new Shape();
                result.pieceShape = pieceShape;
        
                for (int i = 0; i < 4; i++) {
                    result.setX(i, y(i));
                    result.setY(i, -x(i));
                }
                return result;
            }
        
            Shape rotateRight() {
                if (pieceShape == Tetrominoes.SquareShape) {
                    return this;
                }
        
                Shape result = new Shape();
                result.pieceShape = pieceShape;
        
                for (int i = 0; i < 4; i++) {
                    result.setX(i, -y(i));
                    result.setY(i, x(i));
                }
                return result;
            }
        }
        
        private static class ScoreDatabase implements AutoCloseable {
            private Connection conn;
            private static final String DB_URL = "jdbc:mysql://localhost:3306/tetris?serverTimezone=UTC";
            private static final String USER = "game_user";
            private static final String PASS = "9918917988Abc";
        
            public ScoreDatabase() {
                try {
                    Class.forName("com.mysql.cj.jdbc.Driver");
                    conn = DriverManager.getConnection(DB_URL, USER, PASS);
                    createTable();
                    createUserTable();
                    System.out.println("MySQL数据库连接成功");
                } catch (ClassNotFoundException | SQLException e) {
                    System.err.println("数据库初始化失败: " + e.getMessage());
                    LOGGER.log(Level.SEVERE, "数据库初始化失败", e);
                    conn = null;
                }
            }
        
            public boolean isConnected() {
                try {
                    return conn != null && !conn.isClosed();
                } catch (SQLException e) {
                    LOGGER.log(Level.WARNING, "检查数据库连接状态失败", e);
                    return false;
                }
            }
        
            private void createTable() throws SQLException {
                String sql = "CREATE TABLE IF NOT EXISTS scores ("
                        + "id INT PRIMARY KEY AUTO_INCREMENT,"
                        + "name VARCHAR(50) NOT NULL,"
                        + "score INT NOT NULL,"
                        + "date DATE"
                        + ")";
                try (Statement stmt = conn.createStatement()) {
                    stmt.execute(sql);
                }
            }
        
            private void createUserTable() throws SQLException {
                String sql = "CREATE TABLE IF NOT EXISTS users ("
                        + "username VARCHAR(50) PRIMARY KEY,"
                        + "password VARCHAR(32) NOT NULL"
                        + ")";
                try (Statement stmt = conn.createStatement()) {
                    stmt.execute(sql);
                }
            }
        
            public boolean isUsernameExists(String username) throws SQLException {
                if (!isConnected()) throw new SQLException("数据库未连接");
        
                String sql = "SELECT COUNT(*) FROM users WHERE username = ?";
                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setString(1, username);
                    try (ResultSet rs = pstmt.executeQuery()) {
                        if (rs.next()) {
                            return rs.getInt(1) > 0;
                        }
                    }
                }
                return false;
            }
        
            public void registerUser(String username, String hashedPassword) throws SQLException {
                if (!isConnected()) throw new SQLException("数据库未连接");
        
                String sql = "INSERT INTO users (username, password) VALUES (?, ?)";
                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setString(1, username);
                    pstmt.setString(2, hashedPassword);
                    pstmt.executeUpdate();
                }
            }
        
            public boolean validateUser(String username, String hashedPassword) throws SQLException {
                if (!isConnected()) throw new SQLException("数据库未连接");
        
                String sql = "SELECT password FROM users WHERE username = ?";
                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setString(1, username);
                    try (ResultSet rs = pstmt.executeQuery()) {
                        if (rs.next()) {
                            String storedPassword = rs.getString("password");
                            return storedPassword.equals(hashedPassword);
                        }
                    }
                }
                return false;
            }
        
            public void saveGameRecord(String username, int score) {
                if (!isConnected()) {
                    LOGGER.warning("无法保存分数：数据库未连接");
                    return;
                }
        
                String sql = "INSERT INTO scores(name, score, date) VALUES(?, ?, ?)";
                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setString(1, username);
                    pstmt.setInt(2, score);
                    pstmt.setDate(3, java.sql.Date.valueOf(java.time.LocalDate.now()));
                    pstmt.executeUpdate();
                } catch (SQLException e) {
                    System.err.println("保存分数失败: " + e.getMessage());
                    LOGGER.log(Level.SEVERE, "保存分数失败", e);
                }
            }
        
            public int getHighScore() {
                if (!isConnected()) return 0;
        
                String sql = "SELECT MAX(score) FROM scores";
                try (Statement stmt = conn.createStatement();
                     ResultSet rs = stmt.executeQuery(sql)) {
                    if (rs.next()) {
                        return rs.getInt(1);
                    }
                } catch (SQLException e) {
                    System.err.println("获取最高分失败: " + e.getMessage());
                    LOGGER.log(Level.SEVERE, "获取最高分失败", e);
                }
                return 0;
            }
        
            public Score[] getTopScores(int limit) {
                if (!isConnected()) return new Score[0];
        
                String sql = "SELECT name, score, date FROM scores " +
                        "ORDER BY score DESC LIMIT ?";
                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setInt(1, limit);
                    try (ResultSet rs = pstmt.executeQuery()) {
                        List<Score> scores = new ArrayList<>();
                        while (rs.next()) {
                            scores.add(new Score(
                                    rs.getString("name"),
                                    rs.getInt("score"),
                                    rs.getString("date")
                            ));
                        }
                        return scores.toArray(new Score[0]);
                    }
                } catch (SQLException e) {
                    System.err.println("获取高分榜失败: " + e.getMessage());
                    LOGGER.log(Level.SEVERE, "获取高分榜失败", e);
                    return new Score[0];
                }
            }
        
            @Override
            public void close() {
                try {
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                        System.out.println("数据库连接已关闭");
                    }
                } catch (SQLException e) {
                    LOGGER.log(Level.SEVERE, "关闭数据库连接失败", e);
                }
            }
        }
        
        static class Score {
            String name;
            int score;
            String date;
        
public Score(String name, int score, String date) {
                this.name = name;
                this.score = score;
                this.date = date;
            }
        }
        
        // 修复 getStatusBar 方法的实现
        public JLabel getStatusBar() {
            return statusbar;
        }}